source ${path}/flow/conf.tcl
source ${path}/flow/proc.tcl
source ${path}/flow/pgr/pg_psw_conf.tcl



puts "##---------------------------------------------------------------"
puts "## Insert The End Cap Cells"
puts "##---------------------------------------------------------------"

if { ! $PG(dryrun_endcap) } {

#Insert endcap on the boundary
dbDeleteObj [dbget top.insts.name  *xoendcap* -p] ;# delete the manual copy tap cell
deleteFiller -prefix $PG(ENDCAP_prefix)
deleteFiller -prefix VSTACK_

### Prevention insertion for max vertical stack length ###
setFillerMode -reset
setFillerMode -vertical_stack_max_length 29.52
setFillerMode -corePrefix $PG(ENDCAP_prefix)
setFillerMode -vertical_stack_left_edge_cell $PG(ENDCAP_R_REPLACE)
setFillerMode -vertical_stack_right_edge_cell $PG(ENDCAP_L_REPLACE)
setFillerMode -vertical_stack_left_edge_exception_cell $PG(ENDCAP_R_Cell)
setFillerMode -vertical_stack_right_edge_exception_cell $PG(ENDCAP_L_Cell) 

setEndCapMode -reset
setEndCapMode -fitGap true
setEndCapMode -min_jog_width  [expr int(($PG(ENDCAP_R_Width) + $PG(ENDCAP_L_Width) + $PG(core_site) + $PG(uscale) )/$PG(core_site))]
setEndCapMode -min_jog_height 3
setEndCapMode -min_vertical_channel_width   [expr int(($PG(ENDCAP_R_Width) + $PG(ENDCAP_L_Width) + $PSW(global_psw_cell_width) + $PG(uscale) )/$PG(core_site))]
setEndCapMode -min_horizontal_channel_width 3

set pd_list [dbget -u -e [dbget -p top.pds.group {.area > 0} -p].name]
if { [llength $pd_list] > 0 } {
  foreach pd_name $pd_list {  

    if { [lsearch $PG(domain_psw) $pd_name ] < 0 } { 
      #workaround the for boundary tap insertion
      setEndCapMode -boundary_tap true
      set_well_tap_mode -reset
      set_well_tap_mode -top_tap_cell [lindex $PG(ENDCAP_T_Cell) 0] -bottom_tap_cell [lindex $PG(ENDCAP_B_Cell) 0]
      set_well_tap_mode -rule $PG(pgPitch)
      setEndCapMode 								\
                    -prefix            $PG(ENDCAP_prefix)			\
                    -topEdge           $PG(ENDCAP_T_Cell) 		  	\
                    -bottomEdge        $PG(ENDCAP_B_Cell) 			\
                    -leftEdge          $PG(ENDCAP_L_Cell) 			\
                    -leftTopCorner     $PG(ENDCAP_TL_OuterCorner) 		\
                    -leftBottomCorner  $PG(ENDCAP_BL_OuterCorner) 		\
                    -rightEdge         $PG(ENDCAP_R_Cell) 			\
                    -rightTopEdge      $PG(ENDCAP_TL_InnerCorner) 		\
                    -rightBottomEdge   $PG(ENDCAP_BR_InnerCorner)		\
                    -rightTopEdgeNeighbor $PG(ENDCAP_TR_Neighbor) 		\
                    -rightBottomEdgeNeighbor $PG(ENDCAP_BR_Neighbor)
                   # -leftTopEdge       $PG(ENDCAP_L_Cell) 			\
                   # -leftBottomEdge    $PG(BOUNDARY_NINCORNER) 			\
                   # -rightTopCorner    $PG(ENDCAP_TR_OuterCorner) 		\
                   # -rightBottomCorner $PG(ENDCAP_BR_OuterCorner) 		\

    } else {
      #workaround the for boundary tap insertion
      setEndCapMode -boundary_tap true
      set_well_tap_mode -reset
      set_well_tap_mode -top_tap_cell [lindex $PG(ENDCAP_T_Cell_Vpp) 0] -bottom_tap_cell [lindex $PG(ENDCAP_B_Cell_Vpp) 0]
      set_well_tap_mode -rule $PG(pgPitch)
      setEndCapMode 							\
                    -prefix            $PG(ENDCAP_prefix)			\
                    -topEdge           $PG(ENDCAP_T_Cell) 		  	\
                    -bottomEdge        $PG(ENDCAP_B_Cell) 			\
                    -leftEdge          $PG(ENDCAP_L_Cell) 			\
                    -leftTopCorner     $PG(ENDCAP_TL_OuterCorner) 		\
                    -leftBottomCorner  $PG(ENDCAP_BL_OuterCorner) 		\
                    -rightEdge         $PG(ENDCAP_R_Cell) 			\
                    -rightTopEdge      $PG(ENDCAP_TL_InnerCorner) 		\
                    -rightBottomEdge   $PG(ENDCAP_BR_InnerCorner)		\
                    -rightTopEdgeNeighbor $PG(ENDCAP_TR_Neighbor) 		\
                    -rightBottomEdgeNeighbor $PG(ENDCAP_BR_Neighbor)
    }
    #addFiller -prevent_vertical_stack_max_length_violation -powerDomain $pd_name 
    addEndCap -powerDomain $pd_name
  }

} else {
  setEndCapMode 							\
                    -prefix            $PG(ENDCAP_prefix)			\
                    -topEdge           $PG(ENDCAP_T_Cell) 		  	\
                    -bottomEdge        $PG(ENDCAP_B_Cell) 			\
                    -leftEdge          $PG(ENDCAP_L_Cell) 			\
                    -leftTopCorner     $PG(ENDCAP_TL_OuterCorner) 		\
                    -leftBottomCorner  $PG(ENDCAP_BL_OuterCorner) 		\
                    -rightEdge         $PG(ENDCAP_R_Cell) 			\
                    -rightTopEdge      $PG(ENDCAP_TL_InnerCorner) 		\
                    -rightBottomEdge   $PG(ENDCAP_BR_InnerCorner)		\
                    -rightTopEdgeNeighbor $PG(ENDCAP_TR_Neighbor) 		\
                    -rightBottomEdgeNeighbor $PG(ENDCAP_BR_Neighbor)
  	
  #addFiller -prevent_vertical_stack_max_length_violation 
  addEndCap  
}


##-------------------------------------------------------------------"
## work around the drc caused by boundry cell incorrection insertion "
##-------------------------------------------------------------------"

setEcoMode -honorDontTouch false -refinePlace false -honorPowerIntent false -honorFixedStatus false -honorDontUse false  
setEcoMode -updatetiming false
setEcoMode -LEQCheck false
setEcoMode -batchMode true


#fix vstack drc in core left boundary
foreach {x1 y1 x2 y2 } [join $PG(core_bbox)] {
  set y [expr 0.96 + $y1]
  while { $y < $y2 } {
    set box  "$x1 [expr $y + $PG(core_row)/4] $x2 [expr $y + $PG(core_row)/2 ]"
    set insts [dbget -p -e [dbget -p2 [dbQuery -area "$box" -objType inst].cell.name $PG(ENDCAP_R_Cell)].name $PG(ENDCAP_prefix)*]
    foreach inst $insts {
      ecoChangeCell -inst [dbget $inst.name] -cell $PG(ENDCAP_L_REPLACE)
      
    }
    set y [expr $y + 29.52]
  }
} 

#fix vstack drc in core right boundary
foreach {x1 y1 x2 y2 } [join $PG(core_bbox)] {
  set y [expr 0.96 + $y1 + 14.88 ]
  while { $y < $y2 } {
    set box  "$x1 [expr $y + $PG(core_row)/4] $x2 [expr $y + $PG(core_row)/2 ]"
    set insts [dbget -p -e [dbget -p2 [dbQuery -area "$box" -objType inst].cell.name $PG(ENDCAP_L_Cell)].name $PG(ENDCAP_prefix)*]
    foreach inst $insts {
      ecoChangeCell -inst [dbget $inst.name] -cell $PG(ENDCAP_R_REPLACE)
      dbset $inst.pt_x [expr [dbget $inst.pt_x] - $PG(core_site) ]
    }
    set y [expr $y + 29.52]
  }
} 

setEcoMode -reset

#case: (DRC H240.CMD.S.7) reduntant ENDCAP replace cells which is not boundary 
set objs      [dbget -e -u -p2 top.insts.cell.name -regexp "$PG(ENDCAP_L_REPLACE)|$PG(ENDCAP_R_REPLACE)"] 
if { [llength $objs] > 0 } {
  set sbox      [dbshape -output rect [dbget $objs.box] SIZEY [expr -$PG(mfgGrid)]] 
  set b_objs    [dbget -e -p2 [dbQuery -objType inst -areas $sbox -abut_only].cell.name -regexp "$PG(ENDCAP_R_Cell)|$PG(ENDCAP_L_Cell)"] 
  if { [llength $b_objs] > 0 } {
    set sbox      [dbshape -output rect [dbget $b_objs.box] SIZEY [expr -$PG(mfgGrid)]] 
    set insts     [dbget -u -e [dbget -p2 [dbQuery -objType inst -areas $sbox -abut_only].cell.name -regexp "$PG(ENDCAP_L_REPLACE)|$PG(ENDCAP_R_REPLACE)"].name ] 
    foreach inst $insts {
      deleteFiller -inst $inst
    } 
  }
}

#case: ENDCAP replace cell which is not aligned the boundary cell 
#left boundary fix cell  
set margin    [expr $PG(mfgGrid) + $PG(core_site) * 2]
set objs      [dbget -u -p2 top.insts.cell.name $PG(ENDCAP_L_REPLACE)] 
set b_objs    [dbget -p2 [dbQuery -objType inst -areas [dbget $objs.box] -abut_only].cell.name $PG(ENDCAP_R_Cell)] 
set x_list    [dbget -u -e $b_objs.pt_x]
foreach x $x_list {
  set t_objs  [dbget -e $objs {.pt_x < [expr $x + $margin] && .pt_x > [expr $x - $margin] }]
  set t_objs  [dbget -u -e $t_objs {.pt_x < [expr $x - $PG(mfgGrid)] || .pt_x > [expr $x + $PG(mfgGrid)]}]
  foreach obj $t_objs {
    # move replace boundary cell
    set xa    [dbget -u -e [dbget -p2 [dbQuery -objType inst -areas [dbget $obj.box] -abut_only].cell.name $PG(ENDCAP_R_Cell)].pt_x]
    if {! ( [llength $xa ] > 1 || [llength $xa] < 0) } { 
      set xb    [dbget $obj.pt_x]     
      if { $xb < [expr $xa - $PG(mfgGrid)] } {
        dbset $obj.pt_x $xa
      }
    }
    # delete redunctant replace boundary cell
    set insts  [dbget -u -e [dbget -p2 [dbQuery -objType inst -areas [dbget $obj.box] -abut_only].cell.name $PG(ENDCAP_L_REPLACE)].name]
    foreach inst $insts {
      deleteFiller -inst $inst
    } 
  }
}

#right boundary fix cell
set objs      [dbget -u -p2 top.insts.cell.name $PG(ENDCAP_R_REPLACE)] 
set b_objs    [dbget -p2 [dbQuery -objType inst -areas [dbget $objs.box] -abut_only].cell.name $PG(ENDCAP_L_Cell)] 
set x_list    [dbget -u -e $b_objs.pt_x]
foreach x $x_list {
  set t_objs  [dbget -u -e $objs {.pt_x < [expr $x + $margin] && .pt_x > [expr $x - $margin] }]
  set t_objs  [dbget -u -e $t_objs {.pt_x < [expr $x - $PG(mfgGrid) - $PG(core_site)] || .pt_x > [expr $x + $PG(mfgGrid) - $PG(core_site)]}]
  foreach obj $t_objs {
    # move replace boundary cell
    set xa    [dbget -u -e [dbget -p2 [dbQuery -objType inst -areas [dbget $obj.box] -abut_only].cell.name $PG(ENDCAP_L_Cell)].pt_x]
    if {! ( [llength $xa ] > 1 || [llength $xa] < 0) } { 
      set xb    [dbget $obj.pt_x]     
      if { ! ($xb > [expr $xa + $margin  ] || $xb < [expr $xa - $margin]) } {
        dbset $obj.pt_x [expr $xa - $PG(core_site)]
      }
    }
    # delete redunctant replace boundary cell
    set insts  [dbget -u -e [dbget -p2 [dbQuery -objType inst -areas [dbget $obj.box] -abut_only].cell.name $PG(ENDCAP_R_REPLACE)].name]
    foreach inst $insts {
      deleteFiller -inst $inst
    } 
  }
}

};# !dryrun


if { 0 } {

puts "##---------------------------------------------------------------"
puts "## Insert global tap Cells"
puts "##---------------------------------------------------------------"

catch { deleteFiller -prefix $TAP(prefix) }

if { [llength [dbget -e top.FPlan.pblkgs.name pgPB_tapblk]] > 0 } { 
   catch {deletePlaceBlockage  pgPB_tapblk}
}

foreach pd_name $PG(domain_psw) {

 ## create place blockage between memories since psw have tap  
  set extendX         [expr max($PG(Macro_Blockage_Extend_Value),$PG(Voltage_Blockage_Extend_Value)) + max($PG(ENDCAP_R_Width),$PG(ENDCAP_L_Width)) + $PSW(mem_psw_width) + $PG(core_site) * 2 ]
  set merge_gap_boxes [dbShape -output rect $PDI(domain,$pd_name,mem_insts_boxes) SIZEX [expr $PSW(global_psw_pitch_x) / 2.0] SIZEX [expr -$PSW(global_psw_pitch_x) / 2.0]]
  set pb_boxes        [dbShape -output hrect $PDI(domain,$pd_name,mem_insts_psw_l_p_bboxes) OR $PDI(domain,$pd_name,mem_insts_psw_r_p_bboxes) SIZEX [expr $TAP(pitch_x)/2.0] SIZEX [expr - $TAP(pitch_x)/2.0] SIZEX $extendX ]
  set pb_boxes        [dbShape -output hrect $pb_boxes OR $merge_gap_boxes AND $PG(die_boxes)]
  if { [llength $pb_boxes] > 0 } {
    createPlaceBlockage -boxList [join $pb_boxes] -type hard -name pgPB_tapblk -noCutByCore
  }

  if { [dbget [dbget -p top.FPlan.groups.pd.name $pd_name].isDefault ] } { 
    #set leftOffset   [gridfloor [expr $TAP(offset_x) - $TAP(width)/2 ] $PG(core_site)]
    set leftOffset   [gridfloor [expr $TAP(start_x) - $PG(core_x1)]  $PG(core_site)]
    if { ! $PG(dryrun_welltap) } { 
      addWellTap -cell $TAP(WELLTAP_Cell) -cellInterval [expr $TAP(pitch_x)*2] -inRowOffset $leftOffset -prefix $TAP(prefix) -powerDomain $pd_name -checkerBoard -fixedGap 
    } ;# ! dryrun
  } else {
    # check the power domain if disjoint
    if { [llength [dbshape -output polygon $PDI(domain,$pd_name,coresite_boxes)]] < 2 } { 

      # single continuous polygon/rectangle
      foreach {x1 y1 x2 y2} [join $PDI(domain,$pd_name,coresite_bbox)] { break }
      #set leftOffset   [gridfloor [expr $TAP(pitch_x) - fmod( ($x1 - $PG(core_x1) - $TAP(offset_x) + $TAP(width)/2) , $TAP(pitch_x))] $PG(core_site)]   
      set leftOffset   [gridfloor [expr $TAP(pitch_x) - fmod( ($x1 - $TAP(start_x)) , $TAP(pitch_x))] $PG(core_site)]   
      if { ! $PG(dryrun_welltap) } { 
        addWellTap -cell $TAP(WELLTAP_Cell) -cellInterval [expr $TAP(pitch_x)*2] -inRowOffset $leftOffset -prefix $TAP(prefix) -powerDomain $pd_name -checkerBoard -fixedGap 
      } ;# ! dryrun

    } else {
      # addWellTap will add tap in every box, the leftoffset will have difference even through the area is continious
      # multiple discrete polygon/rectangle
      foreach box [dbshape -output hrect $PDI(domain,$pd_name,coresite_boxes)] { 
        foreach {x1 y1 x2 y2} [join $box] {}
        #set leftOffset   [gridfloor [expr $TAP(pitch_x) - fmod( ($x1 - $PG(core_x1) - $TAP(offset_x) + $TAP(width)/2) , $TAP(pitch_x))] $PG(core_site)]    
        set leftOffset   [gridfloor [expr $TAP(pitch_x) - fmod( ($x1 - $TAP(start_x)) , $TAP(pitch_x))] $PG(core_site)]    
        if { ! $PG(dryrun_welltap) } { 
          addWellTap -cell $TAP(WELLTAP_Cell) -cellInterval [expr $TAP(pitch_x)*2] -inRowOffset $leftOffset -prefix $TAP(prefix) -powerDomain $pd_name -checkerBoard -fixedGap -area $box
        } ;# ! dryrun
      }

    };#multiple polygons
  }

  if { [llength [dbget -e top.FPlan.pblkgs.name pgPB_tapblk]] > 0 } { 
    catch {deletePlaceBlockage  pgPB_tapblk}
  }

  Puts "PR-info: move the tap cell abutting boundary to metal5 stripes over the additional boundary psw"
  set boxes [dbshape -output hrect $PDI(domain,$pd_name,global_psw_bndy_left_boxes) OR $PDI(domain,$pd_name,global_psw_bndy_right_boxes)]
  set boxes [dbshape -output hrect $boxes OR $PDI(domain,$pd_name,macro_gap_l_boxes) OR $PDI(domain,$pd_name,macro_gap_m_boxes) OR $PDI(domain,$pd_name,macro_gap_r_boxes) ]
  
  foreach box $boxes {
    foreach {x1 y1 x2 y2} [join $box] { break }
    set insts [dbget -e -p2 [dbQuery -area "$box" -objType inst].cell.name $TAP(WELLTAP_Cell)]
    if { [llength $insts] > 0 } {
      dbSet  $insts.pt_x [expr $x1 + [gridfloor [expr ($PSW(global_psw_cell_bndy_width) - $TAP(width) ) / 2.0 ] $PG(core_site)]]
    }
  }

  # delete the redundant tap cell closed to memory psw cell 
  #puts "PR-info: delete the redundant tap cell near the power switch cell for memories"
  #set psw_boxes [dbshape -output rect [dbget -e [dbget -p top.insts.name *$PSW(mem_psw_prefix)*].boxes] SIZEX [expr max($TAP(width)/2,$PSW(global_psw_cell_width)) ]]
  #foreach box $psw_boxes {
  #  catch {deleteFiller -area $box -prefix $TAP(prefix)}
  #}


  set tap_boxes {}

  Puts "PR-info: calculate the area besides memory"
  # insert the tap cell into the row missed psw cell for memory 
  if { [info exists PDI(domain,$pd_name,mem_insts_psw_l_pri_bboxes)] } {
    foreach box  $PDI(domain,$pd_name,mem_insts_psw_l_pri_bboxes) {
      foreach {x1 y1 x2 y2 } [join $box] { }
      set x  [expr $x1 + [gridfloor [expr ($PSW(mem_psw_width) - $TAP(width)) /2] $PG(core_site)]] 
      lappend tap_boxes [list $x $y1 [expr $x + $TAP(width)] $y2]
    }
  }

  if { [info exists PDI(domain,$pd_name,mem_insts_psw_r_pri_bboxes)] } {
    foreach box  $PDI(domain,$pd_name,mem_insts_psw_r_pri_bboxes) {
      foreach {x1 y1 x2 y2 } [join $box] { }
      set x  [expr $x1 + [gridfloor [expr ($PSW(mem_psw_width) - $TAP(width)) /2 - $PG(core_site)] $PG(core_site)]] 
      lappend tap_boxes [list $x $y1 [expr $x + $TAP(width)] $y2]
    }
  }
  
  Puts "PR-info: calculate the boundary area that are far away tap cell ( > 1/2 $TAP(pitch_x)*2 )"
  foreach box $PDI(domain,$pd_name,global_psw_bndy_left_boxes) {
    foreach {x1 y1 x2 y2 } [join $box] { }
    set xd [expr $TAP(pitch_x) - fmod(($x1 - $TAP(offset_x)) , $TAP(pitch_x))] 
    if { $xd > [expr $TAP(pitch_x) / 2 + $PSW(global_psw_pitch_x) /2] }  {
      set x  [expr $x1 + $TAP(start_x) - $PSW(global_psw_start_x)]
      lappend tap_boxes [list $x $y1 [expr $x + $TAP(width)] $y2]
    }
  }

  foreach box $PDI(domain,$pd_name,global_psw_bndy_right_boxes) {
    foreach {x1 y1 x2 y2 } [join $box] { }
    set xd [expr fmod(($x1 + $TAP(width) - $TAP(offset_x)) , $TAP(pitch_x))] 
    if { $xd > [expr $TAP(pitch_x) / 2 + $PSW(global_psw_pitch_x) /2] }  {
      set x  [expr $x1 + $TAP(start_x) - $PSW(global_psw_start_x)]
      lappend tap_boxes [list $x $y1 [expr $x + $TAP(width)] $y2]
    }
  }

  Puts "PR-info: calculate the gap area between placement blockages"
  foreach box $PDI(domain,$pd_name,macro_gap_l_boxes) {
    foreach {x1 y1 x2 y2 } [join $box] { }
    set xd [expr fmod(($x1 + $TAP(width) - $TAP(offset_x)) , $TAP(pitch_x))] 
    if { $xd > [expr $TAP(pitch_x) / 2 + $PSW(global_psw_pitch_x) /2] }  {
      set x  [expr $x1 + $TAP(start_x) - $PSW(global_psw_start_x)]
      lappend tap_boxes [list $x $y1 [expr $x + $TAP(width)] $y2]
    }
  }

  foreach box $PDI(domain,$pd_name,macro_gap_r_boxes) {
    foreach {x1 y1 x2 y2 } [join $box] { }
echo "$x1 "
    set xd [expr $TAP(pitch_x) - fmod(($x1 - $TAP(offset_x)) , $TAP(pitch_x))] 
    if { $xd > [expr $TAP(pitch_x) / 2 + $PSW(global_psw_pitch_x) /2] }  {
      set x  [expr $x1 + $TAP(start_x) - $PSW(global_psw_start_x)]
      lappend tap_boxes [list $x $y1 [expr $x + $TAP(width)] $y2]
    }
  }

  foreach box  $PDI(domain,$pd_name,macro_gap_m_boxes) {
    foreach {x1 y1 x2 y2 } [join $box] { }
    set x  [expr $x1 + $TAP(start_x) - $PSW(global_psw_start_x)]
    lappend tap_boxes [list $x $y1 [expr $x + $TAP(width)] $y2]
  }

  Puts "PR-info: calculate the y gap area between placement blockages"
  # add additional tap cell for the y gap between macros
  foreach box  $PDI(domain,$pd_name,macro_ygap_boxes) {
    foreach {x1 y1 x2 y2 } [join $box] { }
    set x  [expr $x1 + $TAP(start_x) - $PSW(global_psw_start_x)]
    lappend tap_boxes [list $x $y1 [expr $x + $TAP(width)] $y2]
  }

  if {  [llength $tap_boxes] > 0 } {
    set blk_boxes [dbshape -output rect $PG(die_boxes) ANDNOT $tap_boxes]
    if { [llength $blk_boxes] > 0} {
      createPlaceBlockage -name pgPB_tapblk -boxList [join $blk_boxes] 
      Puts "PR-info: add tap cell for the area without global tap cells"
      addWellTap -cell $TAP(WELLTAP_Cell)  -cellInterval $TAP(pitch_x) -powerDomain $pd_name -prefix WELLTAP_mem_gap_bndy -checkerBoard
      deletePlaceBlockage pgPB_tapblk 
    } 
  }

  Puts "PR-info: calculate the area near placement blockages(>tap pitch) "
  set boxes1     [dbShape -output hrect [dbget -e [dbget -p top.FPlan.pBlkgs.type hard ].boxes] SIZEY [expr $PG(core_row)]]
  set boxes1     [dbShape -output hrect $boxes1 SIZEX  $TAP(pitch_x) ANDNOT $boxes1 AND $PDI(domain,$pd_name,coresite_boxes)]

  foreach box $boxes1 {
    set box    [dbShape -output hrect $box SIZEY [expr - $PG(core_row) /2 + $PG(mfgGrid)] SIZEY [expr $PG(core_row) /2 - $PG(mfgGrid) ] ]
    if {[llength $box] > 0 } {
      set p_boxes [dbget -e [dbget -p2 [dbQuery -area "$box" -objType inst].cell.name "HDR*"].boxes]
      set t_boxes [dbget -e [dbget -p2 [dbQuery -area "$box" -objType inst].cell.name "TAP*"].boxes]
      set b_boxes [dbget -e [dbget -p2 [dbQuery -area "$box" -objType inst].cell.name "BOUNDARY*"].boxes]
      set boxes2  [dbShape -output hrect $p_boxes OR $t_boxes SIZEX $TAP(pitch_x) SIZEY [expr $PG(core_row) /2] OR $b_boxes]
      set boxes2  [dbShape -output hrect $box ANDNOT $boxes2]
      if { [llength $boxes2] > 0 } {
       
        set boxes3 [dbShape -output hrect $p_boxes SIZEY $PG(core_row) AND $PDI(domain,$pd_name,coresite_boxes)]
        set boxes3 [lsort -index 0 -increasing $boxes3]
        if { [llength $boxes3] < 1 } {
          createMarker -type Tap -bbox [join $box] -desc "tap area missed psw cells" -tool user_scrpts -subtype "missed_psw" 
          continue
        }  elseif {[llength $boxes3] > 2 } {
          set boxes4 [list [lindex $boxes3 0] [lindex $boxes3 end]]
        } else {
          set boxes4 [list [lindex $boxes3 0] ]
        };#if [llength $boxes3]

        foreach {xb1 yb1 xb2 yb2 } [join $box] { }
        foreach b4 $boxes4 {
          foreach {x1 y1 x2 y2 } [join $b4] { }
          set x  [expr $x1 + $TAP(start_x) - $PSW(global_psw_start_x)]
          lappend tap_boxes [list $x $yb1 [expr $x + $TAP(width)] $yb2]
        }

      };#if [llength $boxes2]
    };#if [llength $box]
  };#foreach

  #createRouteBlk -layer M7 -name debug -boxList [join $tap_boxes]

  Puts "PR-info: Add tap cell in the gap"
  if {  [llength $tap_boxes] > 0 } {
    set blk_boxes [dbshape -output rect $PG(die_boxes) ANDNOT $tap_boxes]
    if { [llength $blk_boxes] > 0} {
      createPlaceBlockage -name pgPB_tapblk -boxList [join $blk_boxes] 
      Puts "PR-info: add tap cell for the area without global tap cells"
      addWellTap -cell $TAP(WELLTAP_Cell)  -cellInterval $TAP(pitch_x) -powerDomain $pd_name -prefix WELLTAP_mem_gap_bndy -checkerBoard
      deletePlaceBlockage pgPB_tapblk 
    } 
  }

};#domain_psw  

# work around the tap cell be placed as MY
# dbSet [dbget -e -p [dbget -p2 top.insts.cell.name $TAP(WELLTAP_Cell)].orient MY].orient R0
# dbSet [dbget -e -p [dbget -p2 top.insts.cell.name $TAP(WELLTAP_Cell)].orient R180].orient MX

## for the powerdomain without psw
set pd_list [dbget -u -e [dbget -p top.pds.group {.area > 0} -p].name]
foreach pd_name $pd_list {

  if { [lsearch $PG(domain_psw) $pd_name ] > -1 } { continue }

  if { [dbget [dbget -p top.FPlan.groups.pd.name $pd_name].isDefault ] } { 
    #set leftOffset  [gridfloor [expr $TAP(offset_x) - $TAP(width)/2 ] $PG(core_site)]
    set leftOffset  [gridfloor [expr $TAP(start_x) - $PG(core_x1)] $PG(core_site)]
  } else {
    foreach {x1 y1 x2 y2} [join $PDI(domain,$pd_name,coresite_bbox)] { break }
    #set leftOffset  [gridfloor [expr $TAP(pitch_x) - fmod( ($x1 - $TAP(offset_x) + $TAP(width)/2 ) , $TAP(pitch_x))] $PG(core_site)]    
    set leftOffset  [gridfloor [expr $TAP(pitch_x) - fmod( ($x1 - $TAP(start_x)) , $TAP(pitch_x))] $PG(core_site)]    
  }

  if { ! $PG(dryrun_welltap) } { 
    addWellTap -cell  $TAP(AON_WELLTAP_Cell)  -checkerBoard -cellInterval [expr $TAP(pitch_x) *2] -inRowOffset $leftOffset -powerDomain $pd_name
  } ;# ! dryrun
}

##---------------------------------------------------------------------------"
## work around the drc(G.4.NP) caused by tap cell abut ENDCAP REPLACE cell   "
##---------------------------------------------------------------------------"
#case: reduntant tap cells which is abut the ENDCAP_R/L_REPLACE cell 
foreach cell [concat $PG(ENDCAP_L_REPLACE) $PG(ENDCAP_R_REPLACE)] {
  set objs      [dbget -e -u -p2 top.insts.cell.name $PG(ENDCAP_L_REPLACE)] 
  if { [llength $objs] > 0 } {
    set sbox      [dbshape -output rect [dbget $objs.box] SIZEY [expr -$PG(mfgGrid)]] 
    set b_objs    [dbget -e -p2 [dbQuery -objType inst -areas $sbox -abut_only].cell.name -regexp "$TAP(AON_WELLTAP_Cell)|$TAP(WELLTAP_Cell)"] 
    if { [llength $b_objs] > 0 } {
      set sbox      [dbshape -output rect [dbget $b_objs.box] SIZEX [expr -$PG(mfgGrid)]] 
      set insts     [dbget -u -e [dbget -p2 [dbQuery -objType inst -areas $sbox -abut_only].cell.name -regexp "$TAP(AON_WELLTAP_Cell)|$TAP(WELLTAP_Cell)" ].name ] 
      foreach inst $insts {
         deleteFiller -inst $inst
      } 
     }
  }
}

}

proc pr_addTAPCell {} {
    puts " add TAP CELL !!!"
    deleteInst WELLTAP*
    addWellTap -cell TAPCELLBWP240H11P57CPDSVT -cellInterval [expr 210*0.057] -inRowOffset [expr 40*0.057] -prefix WELLTAP -checkerBoard -fixedGap
}